use std::sync::{Condvar, Mutex};

use super::SiminkManage;
use crate::SiminkQuitCause;

/// 命令行监视器线程状态
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ManageReadlineStatus {
    /// 正在运行
    Run,
    /// 等待运行
    Wait,
    /// 被外部事件中断(Ctrl-C|...)
    Interrupted,
}

pub(crate) struct ManageReadline {
    status: Mutex<ManageReadlineStatus>,
    notify: Condvar,
}

impl ManageReadline {
    pub(crate) fn new() -> Self {
        Self { status: Mutex::new(ManageReadlineStatus::Wait), notify: Condvar::new() }
    }
}

impl SiminkManage {
    /// 监视器等待通知事件
    ///
    /// 如果监视器状态不是 Run, 则睡眠等待状态转变为 Run
    #[allow(clippy::missing_panics_doc)]
    pub fn readline_wait_run(&self) {
        let mut status = self.readline.status.lock().unwrap();
        while *status != ManageReadlineStatus::Run {
            status = self.readline.notify.wait(status).unwrap();
        }
    }

    /// 命令行监视器通知被中断退出
    pub fn readline_notify_interrupted(&self) {
        self.set_readline_status(ManageReadlineStatus::Interrupted);
        self.request_simink_quit(SiminkQuitCause::HostMonitorInterrupted);
    }

    /// 获取命令监视器状态
    #[allow(clippy::missing_panics_doc)]
    pub fn readline_status(&self) -> ManageReadlineStatus {
        let lock = self.readline.status.lock().unwrap();
        *lock
    }
}

impl SiminkManage {
    /// 通知命令行监视器运行
    ///
    /// 设置命令行监视器状态为 Run, 并通知命令行监视器该状态,
    /// 命令行监视器唤醒后检测到状态为 Run, 应该主动进入运行状态
    pub fn notify_readline_run(&self) {
        self.set_readline_status(ManageReadlineStatus::Run);
        self.readline.notify.notify_one();
    }

    /// 设置命令行监视器状态为 Wait
    ///
    /// 该函数只能在命令行监视器中调用, 命令行监视器应该在执行完命令后检测自己的状态,
    /// 如果状态为 Wait, 则应该主动进入 Wait 状态, 等待下一次运行事件
    pub fn set_readline_wait(&self) {
        self.set_readline_status(ManageReadlineStatus::Wait);
    }

    fn set_readline_status(&self, status: ManageReadlineStatus) {
        let mut lock = self.readline.status.lock().unwrap();
        *lock = status;
    }
}
